//  Tools for pvm
//  main.c
//  PVM_tool(pvmt)
//
//  Created by Pei Liu on 9/8/11.
//  Copyright 2011 Hong Inc. All rights reserved.
//  @version 0.1(09092011) -c to opcode
//               -m to mnemonic
//  @version 0.2 -s gerate input string code 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

void to_opcode(FILE* fin, FILE* fout);
void to_mneneic(FILE* fin, FILE* fout);
char* trim(char* str);
void ascii();

int main (int argc, const char * argv[])
{
    FILE* fin;
    FILE* fout;
    
    const char* add_in;
    const char* add_out;

    if (argc == 4) 
    {
        add_in = argv[2]; 
        fin = fopen(add_in, "r");
        
        add_out = argv[3];
        fout = fopen (add_out, "w");
        
        if (fin == NULL) 
        { 
			printf("Unknown file: %s\n",add_in); exit(2);
        }

        if (strcmp(argv[1],"-c") == 0)
        {
            to_opcode(fin, fout);
            
        }
        else if (strcmp(argv[1],"-m") == 0)
        {
            to_mneneic(fin, fout);
        }
    }
    else if ((argc == 2) && (strcmp(argv[1], "-s") == 0))
    {
        ascii();
    }
    else 
    {
        printf("Usage: %s [-c|-m]<inputfilename> <outputfilename>\n              [-s]\n",argv[0]); 
        exit(1);
    }
		
    fclose(fin);
    fclose(fout);
    
}

void to_opcode(FILE* fin, FILE* fout)
{
    char* op = (char*)malloc(6);
    int arg1, arg2;
    
    while (fscanf(fin, "%s%d%d", op, &arg1, &arg2) == 3) 
    {
        int opcode = 0;
        op = trim(op);
        
        if (strcmp(op, "mov") == 0) 
        {
            opcode = 1;
        }
        else if (strcmp(op, "mvi") == 0) 
        {
            opcode = 2;
        }
        else if (strcmp(op, "mif") == 0) 
        {
            opcode = 3;
        }
        else if (strcmp(op, "mit") == 0) 
        {
            opcode = 4;
        }
        else if (strcmp(op, "lri") == 0) 
        {
            opcode = 5;
        }
        else if (strcmp(op, "ldr") == 0) 
        {
            opcode = 6;
        }
        else if (strcmp(op, "str") == 0) 
        {
            opcode = 7;
        }
        else if (strcmp(op, "mvr") == 0) 
        {
            opcode = 8;
        }
        else if (strcmp(op, "add") == 0) 
        {
            opcode = 9;
        }
        else if (strcmp(op, "addri") == 0) 
        {
            opcode = 10;
        }
        else if (strcmp(op, "sub") == 0) 
        {
            opcode = 11;
        }
        else if (strcmp(op, "mul") == 0) 
        {
            opcode = 12;
        }
        else if (strcmp(op, "div") == 0) 
        {
            opcode = 13;
        }
        else if (strcmp(op, "or") == 0) 
        {
            opcode = 14;
        }
        else if (strcmp(op, "and") == 0) 
        {
            opcode = 15;
        }
        else if (strcmp(op, "not") == 0) 
        {
            opcode = 16;
        }
        else if (strcmp(op, "b") == 0) 
        {
            opcode = 17;
        }
        else if (strcmp(op, "beq") == 0) 
        {
            opcode = 18;
        }
        else if (strcmp(op, "bne") == 0) 
        {
            opcode = 19;
        }
        else if (strcmp(op, "bgt") == 0) 
        {
            opcode = 20;
        }
        else if (strcmp(op, "bge") == 0) 
        {
            opcode = 21;
        }
        else if (strcmp(op, "blt") == 0) 
        {
            opcode = 22;
        }
        else if (strcmp(op, "ble") == 0) 
        {
            opcode = 23;
        }
        else if (strcmp(op, "pushd") == 0) 
        {
            opcode = 24;
        }
        else if (strcmp(op, "pushr") == 0) 
        {
            opcode = 25;
        }
        else if (strcmp(op, "pushi") == 0) 
        {
            opcode = 26;
        }
        else if (strcmp(op, "popd") == 0) 
        {
            opcode = 27;
        }
        else if (strcmp(op, "popr") == 0) 
        {
            opcode = 28;
        }
        else if (strcmp(op, "puti") == 0) 
        {
            opcode = 29;
        }
        else if (strcmp(op, "puts") == 0) 
        {
            opcode = 30;
        }
        else if (strcmp(op, "line") == 0) 
        {
            opcode = 31;
        }
        else if (strcmp(op, "geti") == 0) 
        {
            opcode = 32;
        }
        else if (strcmp(op, "gets") == 0) 
        {
            opcode = 33;
        }
        else if (strcmp(op, "call") == 0) 
        {
            opcode = 34;
        }
        else if (strcmp(op, "ret") == 0) 
        {
            opcode = 35;
        }
        else if (strcmp(op, "stop") == 0) 
        {
            opcode = 36;
        }
        
        printf("%d\n%d\n%d\n", opcode, arg1, arg2);
        fprintf(fout, "%d\n%d\n%d\n", opcode, arg1, arg2);
    }
}

void to_mneneic(FILE* fin, FILE* fout)
{
    char* opcode[37] = {"pvm(invalid)", "mov", "mvi", "mif", "mit", "lri", "ldr", "str", "mvr", "add",
                        "addri", "sub", "mul", "div", "or", "and", "not", "b", "beq", "bne","bgt",
                        "bge","blt", "ble", "pushd", "pushr", "pushi", "popd", "popr","puti", "puts",
                        "line", "geti", "gets", "call", "ret", "stop"};
    
    int ocode, arg1, arg2;
    int opcode_num, str_beg, str_len, entrypoint;
    
    if (fscanf(fin, "%d%d%d%d", &opcode_num, &str_beg, &str_len, &entrypoint) != 4)
        printf("Invalid header!");
    
    printf("Header:\nNumber of opcode: %d\nString begin position: %d\nstringlist length: %d\nProgram entrypoint: %d\n", opcode_num, str_beg, str_len, entrypoint);
    fprintf(fout, "Header:\nNumber of opcode: %d\nString begin position: %d\nstringlist length: %d\nProgram entrypoint: %d\n", opcode_num, str_beg, str_len, entrypoint);


    int i = 0;
    for (i = 0; i < opcode_num; i += 3) 
    {
        if (fscanf(fin, "%d%d%d", &ocode, &arg1, &arg2) == 3)
        {
            if((ocode >= 1) && (ocode <= 36))
            {
                printf("%s\t%d\t%d\n", opcode[ocode], arg1, arg2);
                fprintf(fout, "%s\t%d\t%d\n", opcode[ocode], arg1, arg2);
            }
            else
            {
                printf("Invalid opcode: %d\n", ocode);
            }
        }
        else
            printf("Invalid number of opcode");
        
    }
    
    int chr;
    printf("String List:\n");
    
    for(i = 0; i < str_len; i++)
    {
        if (fscanf(fin, "%d", &chr) == 1)
            if (chr == 0)
            {
                printf("\n");
                fprintf(fout, "\n");
            }
            else
            {
                printf("%c", chr);
                fprintf(fout, "%c", chr);
            }
        else
            printf("Invalid String!");

    }
    
}

char* trim(char* str)
{
    int i = 0;
    
    if (str)
    {
        //Remove leading spaces
        char* ibuf = str;
        for (ibuf = str; *ibuf && isspace(*ibuf); ++ibuf)
            ++str;
   
        
        //Remove trailing spaces
        char* obuf = str;
        i = (int)strlen(str);
        
        while (--i >= 0)
        {
            if (!isspace(obuf[i]))
                break;
        }
        
        obuf[++i] = '\0';
    }
    return str;
}

void ascii()
{
    int temp_add;
    char temp;
    
    printf("Start address?      ");
    scanf("%d", &temp_add);
    
    printf("Input the string:\n");
    
    while ((temp = getchar()) != '\n' && temp != EOF);
    
    while(scanf("%c", &temp) == 1)
    {
        if (temp == '\n')
        {
            printf("mvi %d %d\n",temp_add,0);
            printf("\nContinue? (y/n)");
            char temp0 = getchar();
            if (temp0 == 'n') 
            {
                exit(0);
            }
            while ((temp0 = getchar()) != '\n' && temp0 != EOF);
        }
        else
        {
            printf("mvi %d %d\n",temp_add,(int)temp);
            temp_add++;
        }
        
    }

}


